package cn.fintecher.pangolin.service.manage.service;

import cn.fintecher.pangolin.common.enums.BaseSelect;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.utils.BeanUtils;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.mysql.*;
import cn.fintecher.pangolin.service.manage.repository.ResourceRepository;
import cn.fintecher.pangolin.service.manage.repository.RoleRepository;
import cn.fintecher.pangolin.service.manage.repository.UserRepository;
import cn.fintecher.pangolin.service.manage.request.*;
import cn.fintecher.pangolin.service.manage.response.RoleResponse;
import cn.fintecher.pangolin.service.manage.response.RoleUserResponse;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.modelmapper.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Auther: xiaqun
 * @Description:
 * @Date: 9:48 2019/8/14
 */

@Service("roleService")
@Transactional(rollbackFor = Exception.class)
public class RoleService {
    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private BaseService baseService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ResourceRepository resourceRepository;

    @Autowired
    private ModelMapper modelMapper;

    /**
     * 新增角色
     */
    public void addRole(AddRoleRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(QRole.role.name.eq(request.getName()));
        boolean exists = roleRepository.exists(booleanBuilder);
        if (exists) {
            throw new BadRequestException(null, "addRole", "role.is.exists");
        }
        Role role = new Role();
        BeanUtils.copyPropertiesIgnoreNull(request, role);
        role.setIsSystem(BaseSelect.NO);
        role.process(userModel.getId(), ZWDateUtil.getNowDateTime(), true);
        roleRepository.save(role);
    }

    /**
     * 修改角色
     */
    public void modifyRole(ModifyRoleRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(QRole.role.name.eq(request.getName()))
                .and(QRole.role.id.ne(request.getRoleId()));
        boolean exists = roleRepository.exists(booleanBuilder);
        if (exists) {
            throw new BadRequestException(null, "addRole", "role.is.exists");
        }
        Role role = roleRepository.findById(request.getRoleId()).orElseThrow(() -> new BadRequestException(null, "role", "role.is.null"));
        if (role.getIsSystem().equals(BaseSelect.YES)) {
            throw new BadRequestException(null, "role", "system.cant.modify");
        }
        if (StringUtils.isNotBlank(request.getName())) {
            role.setName(request.getName());
        }
        if (StringUtils.isNotBlank(request.getDescription())) {
            role.setDescription(request.getDescription());
        }
        if (Objects.nonNull(request.getStatus())) {
            role.setStatus(request.getStatus());
        }
        role.process(userModel.getId(), ZWDateUtil.getNowDateTime(), false);
        roleRepository.save(role);
    }

    /**
     * 删除角色
     */
    public void deleteRole(String roleId, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        Role role = roleRepository.findById(roleId).orElseThrow(() -> new BadRequestException(null, "role", "role.is.null"));
        if (role.getIsSystem().equals(BaseSelect.YES)) {
            throw new BadRequestException(null, "role", "system.cant.delete");
        }
        //处理用户
        Iterable<User> iterable = userRepository.findAll(QUser.user.roles.contains(role));
        if (iterable.iterator().hasNext()) {
            iterable.forEach(e -> {
                e.getRoles().remove(role);
                e.process(userModel.getId(), ZWDateUtil.getNowDateTime(), false);
            });
            userRepository.saveAll(iterable);
        }
        //删除角色
        roleRepository.delete(role);
    }

    /**
     * 分配角色
     */
    public void distributeRole(DistributeRoleRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        Iterable<User> users = userRepository.findAllById(request.getUserIds());
        Iterable<Role> roles = roleRepository.findAllById(request.getRoleIds());
        Set<Role> set = new HashSet<>(IterableUtils.toList(roles));
        users.forEach(e -> {
            e.setRoles(set);
            e.process(userModel.getId(), ZWDateUtil.getNowDateTime(), false);
        });
        userRepository.saveAll(users);
    }

    /**
     * 删除角色下用户
     */
    public void deleteRoleUser(DeleteRoleUserRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        Role role = roleRepository.findById(request.getRoleId()).orElseThrow(() -> new BadRequestException(null, "role", "role.is.null"));
        Iterable<User> iterable = userRepository.findAll(QUser.user.id.in(request.getUserIds()));
        if (iterable.iterator().hasNext()) {
            iterable.forEach(e -> {
                e.getRoles().remove(role);
                e.process(userModel.getId(), ZWDateUtil.getNowDateTime(), false);
            });
        }
        userRepository.saveAll(iterable);
    }

    /**
     * 分配模块权限
     */
    public void distributePermission(DistributePermissionRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        Iterable<Role> roles = roleRepository.findAllById(request.getRoleIds());
        Iterable<Resource> iterable = resourceRepository.findAllById(request.getResources());
        Set<Resource> set = new HashSet<>(IterableUtils.toList(iterable));
        roles.forEach(e -> {
            e.setResources(set);
            e.process(userModel.getId(), ZWDateUtil.getNowDateTime(), false);
        });
        roleRepository.saveAll(roles);
    }

    /**
     * 复制角色
     */
    public void copyRole(String roleId, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        Role role = roleRepository.findById(roleId).orElseThrow(() -> new BadRequestException(null, "role", "role.is.null"));
        Role result = new Role();
        result.setName(role.getName() + "复制");
        result.setStatus(role.getStatus());
        result.setDescription(role.getDescription());
        Set<Resource> set = new HashSet<>(role.getResources());
        result.setResources(set);
        result.process(userModel.getId(), ZWDateUtil.getNowDateTime(), true);
        roleRepository.save(result);
    }

    /**
     * 多条件查询角色
     */
    public Page<RoleResponse> findAllRole(FindRoleRequest request, Pageable pageable) {
        Sort sort = new Sort(Sort.Direction.DESC, "operateTime");
        pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
        Page<Role> page = roleRepository.findAll(request.getBuilder(), pageable);
        return page.map(e -> modelMapper.map(e, RoleResponse.class));
    }

    /**
     * 多条件查询角色下用户
     */
    public Page<RoleUserResponse> findUserByRole(FindUserRequest request, Pageable pageable) {
        Page<User> page = userRepository.findAll(request.getBuilder(), pageable);
        return page.map(e -> modelMapper.map(e, RoleUserResponse.class));
    }

    /**
     * 查询角色下所有资源
     */
    public Set<Resource> findAllResource(String roleId) {
        Role role = roleRepository.findById(roleId).orElseThrow(() -> new BadRequestException(null, "role", "role.is.null"));
        return role.getResources().stream().filter(e -> e.getLevel() == 3).collect(Collectors.toSet());
    }

    /**
     * 查询角色下所有控件
     */
    public Set<Resource> findAllControls(String roleId) {
        Role role = roleRepository.findById(roleId).orElseThrow(() -> new BadRequestException(null, "role", "role.is.null"));
        return role.getResources().stream().filter(e -> e.getLevel() == 4).collect(Collectors.toSet());
    }

    public List<RoleResponse> getAllRoles() {
        Iterable<Role> iterable = roleRepository.findAll(QRole.role.isSystem.eq(BaseSelect.NO));
        Type typeToken = new TypeToken<List<RoleResponse>>() {
        }.getType();
        return modelMapper.map(IterableUtils.toList(iterable), typeToken);
    }

    public Page<RoleResponse> findRoles(RoleRequest roleRequest, Pageable pageable) {
        BooleanBuilder booleanBuilder = roleRequest.generateBooleanBuilder();
        Page<Role> rolePage = roleRepository.findAll(booleanBuilder, pageable);
        return rolePage.map(role -> modelMapper.map(role, RoleResponse.class));
    }

    /**
     * @Author wangxiangdong
     * @Description 批量分配角色
     * @Date 2019/10/24 16:51
     **/
    @Transactional
    public void batchDistributeRole(BatchDistributeRoleRequest request, String token) {
        List<Role> roleList = roleRepository.findAllById(request.getRoleIds());
        Set<Role> roleSet = new HashSet<>(roleList);
        List<User> userList = userRepository.findAllById(request.getUserIds());
        if (userList.size() > 0) {
            userList.forEach(user -> {
                user.setRoles(roleSet);
            });
        }
        userRepository.saveAll(userList);
    }
}
